package pl.org.lutra.planner.model.util;

import pl.org.lutra.planner.model.data.Dive;
import pl.org.lutra.planner.model.data.DiveSegment;

public class DiveOperator {
    
    private Dive dive;
    
    public void setDive(Dive dive) {
        this.dive = dive;
    }
    
    public boolean addSegment() {
        DiveSegment lastSeg = dive.getSegment(dive.getSegments().size() - 1);
        
        DiveSegment seg = new DiveSegment();
        seg.setStartDepth(lastSeg.getTargetDepth());
        seg.setTargetDepth(lastSeg.getTargetDepth());
        
        dive.getSegments().add(seg);
        
        return true;
    }
    
    public boolean deleteSegment(int row) {
        if ((row == 0) && (dive.getSegments().size() == 1)) {
            return false;
        } else {
            // TODO: Implement logic
            
            dive.getSegments().remove(row);
            return true;
        }
    }
    
    public void setTargetDepth(int row, float targetDepth) {
        DiveSegment seg = dive.getSegment(row);
        
        seg.setTargetDepth(targetDepth);
        
        float startDepth = seg.getStartDepth();
        if (startDepth != targetDepth) {
            seg.setTime(ModelUtil.getTravelTime(startDepth, targetDepth));
        }
        
        updateRunTime(row, seg);
        updateNextRuntimes(row + 1, seg.getRuntime());
        
        updateNextStartDepths(row + 1, seg.getTargetDepth());
    }
    
    public void setTime(int row, float time) {
        DiveSegment seg = dive.getSegment(row);
        
        float startDepth = seg.getStartDepth();
        float targetDepth = seg.getTargetDepth();
        if (startDepth > targetDepth) {
            float travelTime = ModelUtil.getTravelTime(startDepth, targetDepth);
            if (time < travelTime) {
                seg.setTime(travelTime);
            }
        } else {
            seg.setTime(time);
        }
        
        updateRunTime(row, seg);
        updateNextRuntimes(row + 1, seg.getRuntime());
    }
    
    public void setRuntime(int row, float runtime) {
        DiveSegment seg = dive.getSegment(row);
        
        float startDepth = seg.getStartDepth();
        float targetDepth = seg.getTargetDepth();
        if (startDepth > targetDepth) {
            float travelTime = ModelUtil.getTravelTime(startDepth, targetDepth);
            DiveSegment prevSeg = dive.getSegment(row - 1);
            seg.setRuntime(travelTime + (prevSeg != null ? prevSeg.getRuntime() : 0));
        } else {
            seg.setRuntime(runtime);
        }
        
        updateTime(row, seg);
        updateNextRuntimes(row + 1, seg.getRuntime());
    }
    
    private void updateRunTime(int row, DiveSegment segment) {
        DiveSegment prevSeg = dive.getSegment(row - 1);
        segment.setRuntime(segment.getTime() + (prevSeg != null ? prevSeg.getRuntime() : 0));
    }
    
    private void updateTime(int row, DiveSegment segment) {
        DiveSegment prevSeg = dive.getSegment(row - 1);
        segment.setTime(segment.getRuntime() - (prevSeg != null ? prevSeg.getRuntime() : 0));
    }
    
    private void updateNextRuntimes(int startRow, float lastRuntime) {
        float runtime = lastRuntime;
        for (int i = startRow; i < dive.getSegments().size(); i++) {
            DiveSegment seg = dive.getSegment(i);
            
            runtime += seg.getTime();
            seg.setRuntime(runtime);
        }
    }
    
    private void updateNextStartDepths(int nextRow, float depth) {
        DiveSegment seg = dive.getSegment(nextRow);
        
        if (seg != null) {
            seg.setStartDepth(depth);
        }
    }
    
}
